﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web;

namespace Acms.DataControls2
{
   /* [ToolboxData("<{0}:AcmsCachedSiteMapDataSource runat=server></{0}:AcmsCachedSiteMapDataSource>")]
    public class AcmsCachedSiteMapDataSource : HierarchicalDataSourceControl
    {
        public AcmsCachedSiteMapDataSource()
        {
            CurrentSiteVersion = DateTime.Now;
        }

        public string MenuName { get; set; }
        public string RootText { get; set; }
        public string ParentPath { get; set; }
        public bool IncludeParent { get; set; }
        public bool FlattenParent { get; set; }
        public int SiteId { get; set; }
        public DateTime? CurrentSiteVersion { get; set; }
        public int MenuId { get; private set; }
        public string CurrentRelativeUrl { get; set; }

        private void EnsureLoaded()
        {
            //if SiteId and Site Version have not been set then do so
            if (SiteId == 0)
            {
                var acmsPage = Page as Acms.AcmsControls.TemplatePage;
                if (acmsPage != null)
                {
                    SiteId = acmsPage.AcmsContext.SiteId;
                    CurrentSiteVersion = acmsPage.AcmsContext.SiteVersion;
                }
            }
            if (MenuId == 0 && !string.IsNullOrEmpty(MenuName))
            {
                Bll.Menu menu = Bll.Menu.GetByNameAndSiteId(MenuName, SiteId);
                if (menu != null)
                {
                    MenuId = menu.Id;
                    if (string.IsNullOrEmpty(ParentPath))
                    {
                        if (CurrentRelativeUrl != null)
                        {
                            ParentPath = menu.ConvertParentPath(CurrentRelativeUrl);
                        }
                        else
                        {
                            ParentPath = menu.ConvertParentPath(Page.Request.AppRelativeCurrentExecutionFilePath);
                        }
                        IncludeParent = menu.IncludeParent;
                    }
                }
            }
        }

        private HierarchicalDataSourceView view;
        protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
        {
            if (view == null)
            {
                EnsureLoaded();
                view = new AcmsCachedSiteMapDataSourceView(this);
            }
            return view;
        }

        internal class PostMenuItem
        {
            public PostMenuItem()
            {
                Children = new List<PostMenuItem>();
            }

            public Bll.Post Post { get; set; }
            public List<PostMenuItem> Children { get; set; }
            public PostMenuItem Parent { get; set; }

            public void Add(PostMenuItem child)
            {
                child.Parent = this;
                Children.Add(child);
            }
        }

        private PostMenuItem RecusiveBuildTree(string parentPath, IEnumerator<Bll.Post> posts)
        {
            var tmp = new PostMenuItem() { Post = posts.Current };
            if (posts.MoveNext())
            {
                if (posts.Current.ParentPath == tmp.Post.ParentPath)
                {
                    tmp.Add(RecusiveBuildTree(tmp.Post.ParentPath, posts);
                }
            }
            return tmp;
        }

        public List<PostMenuItem> BuildTree(List<Bll.Post> posts)
        {
            List<PostMenuItem> list = new List<PostMenuItem>();
            var enumerator = posts.GetEnumerator();
            while(enumerator.MoveNext())
            {
                list.Add(RecusiveBuildTree(enumerator.Current.ParentUrl, enumerator));
            }
            return list;
        }

        public PostMenuItem FindByParentPath(List<PostMenuItem> tree, string parentPath)
        {
            PostMenuItem retVal = null;
            foreach(var item in tree)
            {
                if (item.Post.ParentPath != null && item.Post.ParentPath.Equals(parentPath, StringComparison.CurrentCultureIgnoreCase))
                {
                    retVal = item;
                    break;
                }
                if (retVal == null)
                {
                    retVal = FindByParentPath(item.Children, parentPath);
                }
            }
            return retVal;
        }

        internal List<PostMenuItem> GetInitialForMenu(int menuId)
        {
            //get the posts and build tree
            var posts = Acms.Bll.Post.GetAllByMenuId(SiteId, menuId, this.CurrentSiteVersion);
            var tree = BuildTree(posts);


            List<PostMenuItem> retVal = null;
            if (!string.IsNullOrEmpty(ParentPath))
            {
                var current = FindByParentPath(tree, ParentPath);
                if (current != null)
                {
                    if (IncludeParent || FlattenParent)
                    {
                        //get post by parent path
                        retVal = new[] { current }.ToList();// GetList(Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion));
                    }
                    else
                    {
                        //get children by parent path
                        retVal = current.Parent.Children;//Bll.Post.GetAllBySiteIdMenuIdAndParentPath(SiteId, menuId, ParentPath, CurrentSiteVersion);
                    }
                }
            }
            else
            {
                if (IncludeParent || FlattenParent)
                {
                    //get top level
                    retVal = new[] { tree.FirstOrDefault() }.ToList();//GetList(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                }
                else
                {
                    //get children of home page
                    retVal = tree//Bll.Post.GetAllBySiteIdMenuIdAndParentPath(SiteId, menuId, "~/", CurrentSiteVersion);
                }
            }

            //add in the children if flatten parent
            if (FlattenParent && retVal.Count == 1)
            {
                //get all children
                var clonedChildren = retVal.First().Children.ToArray();
                retVal.First().Children.Clear();
                retVal.AddRange(clonedChildren);// retval.AddRange(Bll.Post.GetAllByMenuIdAndParentGuid(SiteId, menuId, retVal.First().PostGuid, CurrentSiteVersion));
            }
            return retVal;
        }

        internal List<Bll.Post> GetInitialWithoutMenu()
        {
            List<Bll.Post> retVal = null;
            if (!string.IsNullOrEmpty(ParentPath))
            {
                if (IncludeParent || FlattenParent)
                {
                    //get post by parentpath
                    retVal = GetList(Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion));
                }
                else
                {
                    //get children by parent path
                    retVal = Bll.Post.GetAllBySiteIdAndParentPath(SiteId, ParentPath, CurrentSiteVersion);
                }
            }
            else
            {
                if (IncludeParent || FlattenParent)
                {
                    //get top level
                    retVal = GetList(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                }
                else
                {
                    //get children of home page
                    retVal = Bll.Post.GetAllBySiteIdAndParentPath(SiteId, "~/", CurrentSiteVersion);
                }
            }

            if (FlattenParent && retVal.Count == 1)
            {
                retVal.AddRange(Bll.Post.GetAllByParentGuid(SiteId, retVal.First().PostGuid, CurrentSiteVersion));
            }

            return retVal;
        }

        internal List<Bll.Post> GetInitial(bool ignoreRootText)
        {
            if (!ignoreRootText && !string.IsNullOrEmpty(RootText))
            {
                Bll.Post tmp = Bll.Post.CreateInstance();
                tmp.DisplayName = RootText;
                return GetList(tmp);
            }
            else if (MenuId != 0)
            {
                return GetInitialForMenu(MenuId);
            }
            else
            {
                return GetInitialWithoutMenu();
            }
        }

        private bool IsParent(Bll.Post post)
        {
            if (post != null)
            {
                if (post.ParentPath == null)
                {
                    return true;
                }
                else if (post.Path == this.ParentPath || string.Concat(post.Path, "/") == this.ParentPath || post.Path == string.Concat(this.ParentPath, "/"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        internal List<Bll.Post> GetChildren(Bll.Post post)
        {
            if (post == null || post.Id == 0)
            {
                return GetInitial(true);
            }
            else if (FlattenParent && IsParent(post))
            {
                return null;
            }
            else if (MenuId != 0)
            {
                return Bll.Post.GetAllByMenuIdAndParentGuid(SiteId, MenuId, post.PostGuid, CurrentSiteVersion);
            }
            else
            {
                return Bll.Post.GetAllByParentGuid(SiteId, post.PostGuid, CurrentSiteVersion);
            }
        }

        private List<Bll.Post> GetList(Bll.Post post)
        {
            List<Bll.Post> tmp = new List<Acms.Bll.Post>();
            if (post != null)
                tmp.Add(post);
            return tmp;
        }

        protected override object SaveViewState()
        {
            ViewState["SiteId"] = SiteId;
            ViewState["MenuName"] = MenuName;
            ViewState["MenuId"] = MenuId;
            ViewState["ParentPath"] = ParentPath;
            ViewState["RootText"] = RootText;
            ViewState["CurrentSiteVersion"] = CurrentSiteVersion;
            ViewState["CurrentRelativeUrl"] = CurrentRelativeUrl;
            return base.SaveViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            if (ViewState["SiteId"] is int)
                SiteId = (int)ViewState["SiteId"];
            MenuName = ViewState["MenuName"] as string;
            if (ViewState["MenuId"] is int)
                MenuId = (int)ViewState["MenuId"];
            ParentPath = ViewState["ParentPath"] as string;
            RootText = ViewState["RootText"] as string;
            CurrentSiteVersion = ViewState["CurrentSiteVersion"] as DateTime?;
            CurrentRelativeUrl = ViewState["CurrentRelativeUrl"] as string;
        }
    }

    public class AcmsCachedSiteMapDataSourceView : HierarchicalDataSourceView
    {   
        public AcmsCachedSiteMapDataSourceView(AcmsCachedSiteMapDataSource owner) : base() { this.owner = owner; }

        AcmsCachedSiteMapDataSource owner;

        public override IHierarchicalEnumerable Select()
        {
            return new AcmsCachedSiteMapEnumerator(owner.GetInitial(false), owner);
        }
    }

    public class AcmsCachedSiteMapEnumerator : IHierarchicalEnumerable
    {
        public AcmsCachedSiteMapEnumerator(Bll.Post post, AcmsCachedSiteMapDataSource owner)
        {
            this.posts = new List<Acms.Bll.Post>();
            posts.Add(post);
            this.owner = owner;
        }

        public AcmsCachedSiteMapEnumerator(List<Bll.Post> posts, AcmsCachedSiteMapDataSource owner)
        {
            this.posts = posts;
            this.owner = owner;
        }

        AcmsCachedSiteMapDataSource owner;
        #region IHierarchicalEnumerable Members

        public IHierarchyData GetHierarchyData(object enumeratedItem)
        {
            return new AcmsCachedSiteMapData(enumeratedItem as Bll.Post, owner);
        }

        #endregion

        #region IEnumerable Members

        private List<Bll.Post> posts = null;

        public System.Collections.IEnumerator GetEnumerator()
        {
            if (posts != null)
            {
                foreach (Bll.Post p in posts)
                {
                    yield return p;
                }
            }
        }

        #endregion
    }

    public class AcmsCachedSiteMapData : IHierarchyData
    {
        public AcmsCachedSiteMapData(Bll.Post post, AcmsCachedSiteMapDataSource owner)
        {
            this.post = post;
            this.owner = owner;
        }

        AcmsCachedSiteMapDataSource owner;

        private Bll.Post post;

        private List<Bll.Post> children;
        protected List<Bll.Post> Children
        {
            get
            {
                if (children == null)
                {
                    children = owner.GetChildren(post);
                }
                return children;
            }

        }

        #region IHierarchyData Members

        public IHierarchicalEnumerable GetChildren()
        {
            return new AcmsCachedSiteMapEnumerator(Children, owner);
        }

        public IHierarchyData GetParent()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public bool HasChildren
        {
            get { return Children != null && Children.Count > 0; }
        }

        public object Item
        {
            get
            {
                return post;
            }
        }

        public string Path
        {
            get
            {
                if (post != null)
                {
                    return post.Path;
                }
                else
                {
                    return null;
                }
            }
        }

        public string Type
        {
            get
            {
                if (post != null)
                {
                    return post.GetType().ToString();
                }
                else
                {
                    return null;
                }
            }
        }

        #endregion
    }*/
}